﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Unscrambler.Constants;

namespace Unscrambler.Controls
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Unscrambler.Controls"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Unscrambler.Controls;assembly=Unscrambler.Controls"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:ScrambleCanvas/>
    ///
    /// </summary>
    public class ScrambleCanvas : Canvas
    {
        private UIElement last;
        
        private Random rand = new Random();
        
        public static readonly DependencyProperty WordProperty = DependencyProperty.Register(
            "Word", typeof(string), typeof(ScrambleCanvas), 
            new PropertyMetadata(string.Empty, new PropertyChangedCallback(ScrambleCanvas.OnCurrentWordChanged)),
            null);

        public string Word
        {
            get { return (string)this.GetValue(WordProperty); }
            set
            {
                this.SetValue(WordProperty, value);
            }
        }



        private static void OnCurrentWordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ScrambleCanvas canvas = d as ScrambleCanvas;
            if (canvas != null)
            {
                canvas.ResetCanvas();
                
                string word = e.NewValue as string;
                IEnumerable<char> letters = word.ToList();
                Random rand = new Random();
                List<double> leftValues = new List<double>();
                
                foreach (char letter in letters)
                {
                    LetterTile tile = new LetterTile();
                    tile.Letter = letter;
                                                          
                    canvas.CreateNewTransformGroupForElement(tile);
                    canvas.Children.Add(tile);
                    
                }

            }
        }

        public void ResetCanvas()
        {
            this.Children.Clear();
        }

        private void CreateNewTransformGroupForElement(UIElement element)
        {
            TransformGroup tGroup = new TransformGroup();
            
            //RotateTransform rotateTransform = new RotateTransform(rand.Next(360));
            //rotateTransform.CenterX = 50.0;
            //rotateTransform.CenterY = 50.0;
            RotateTransform rotateTransform = new RotateTransform(0);
            tGroup.Children.Add(rotateTransform);
            
            double randomXValue = rand.NextDouble() * (this.Width - SizeConstants.LetterTileSideLength);
            double randomYValue = rand.NextDouble() * (this.Height - SizeConstants.LetterTileSideLength);
            TranslateTransform translateTransform = new TranslateTransform(randomXValue, randomYValue);
            tGroup.Children.Add(translateTransform);
              
            element.RenderTransform = tGroup;
        }

        private TranslateTransform GetTranslateTransformFromUIElement(UIElement itemManipulated)
        {
            TransformGroup myTransform = itemManipulated.RenderTransform as TransformGroup;
            TranslateTransform translateTransform = (TranslateTransform)myTransform.Children.First(x => x is TranslateTransform);
            return translateTransform;
        }

        private RotateTransform GetRotateTransformFromUIElement(UIElement itemManipulated)
        {
            TransformGroup myTransform = itemManipulated.RenderTransform as TransformGroup;
            RotateTransform rotateTransform = (RotateTransform)myTransform.Children.First(x => x is RotateTransform);
            return rotateTransform;
        }

        public ScrambleCanvas()
        {
            //this.ManipulationStarting += this.ScrambleCanvas_ManipulationStarting;
            //this.ManipulationDelta += this.ScrambleCanvas_ManipulationDelta;
            //this.ManipulationInertiaStarting += this.TouchableThing_ManipulationInertiaStarting;
            //this.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(ScrambleCanvas_ManipulationCompleted);
        }

        void ScrambleCanvas_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            UIElement itemManipulated = e.OriginalSource as UIElement;
            if (itemManipulated != null)
            {
                itemManipulated.SetValue(Canvas.TopProperty, DependencyProperty.UnsetValue);
                itemManipulated.SetValue(Canvas.LeftProperty, DependencyProperty.UnsetValue);               
                //TODO: fill this in later when I have a second canvas
                //for the unscrambled word
                // containerBounds = new Rect(MyWrapPanel.RenderSize);
                //Rect objectBounds = itemManipulated.RenderTransform.TransformBounds(new Rect(itemManipulated.RenderSize));
                
                
            }


        }

        void ScrambleCanvas_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = this;

        }

        void ScrambleCanvas_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            UIElement itemManipulated = e.OriginalSource as UIElement;
            if (itemManipulated != null)
            {
               
                
                
                if (last != null) Canvas.SetZIndex(last, 0);
                Canvas.SetZIndex(itemManipulated, 2);
                last = itemManipulated;
                               

                Rect containerBounds = new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);
                Rect objectBounds = itemManipulated.RenderTransform.TransformBounds(new Rect(itemManipulated.RenderSize));



                // the center never changes in this sample, although we always compute it.
                Point center = new Point(itemManipulated.RenderSize.Width / 2.0, itemManipulated.RenderSize.Height / 2.0);

                RotateTransform rotation = this.GetRotateTransformFromUIElement(itemManipulated);

                // apply the rotation at the center of the rectangle if it has changed
                rotation.CenterX = center.X;
                rotation.CenterY = center.Y;
                rotation.Angle += e.DeltaManipulation.Rotation;
                                               
                // apply translation 

                TranslateTransform translateTransform = this.GetTranslateTransformFromUIElement(itemManipulated);
                translateTransform.X += e.DeltaManipulation.Translation.X;
                translateTransform.Y += e.DeltaManipulation.Translation.Y;

                if (e.IsInertial && !containerBounds.Contains(objectBounds))
                {
                    e.Complete();
                    //Report that we have gone over our boundary 
                    e.ReportBoundaryFeedback(e.DeltaManipulation);
                    e.Handled = true;

                    if (objectBounds.Left < containerBounds.Left)
                    {
                        translateTransform.X = containerBounds.Left;
                    }
                    if (objectBounds.Right > containerBounds.Right)
                    {
                        translateTransform.X = containerBounds.Right - objectBounds.Width;
                    }
                    if (objectBounds.Top < containerBounds.Top)
                    {
                        translateTransform.Y = containerBounds.Top;
                    }
                    if (objectBounds.Bottom > containerBounds.Bottom)
                    {
                        translateTransform.Y = containerBounds.Bottom - objectBounds.Height;
                    }

                }
             }
        }

        void TouchableThing_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {

            // Decrease the velocity of the Rectangle's movement by 
            // 10 inches per second every second.
            // (10 inches * 96 DIPS per inch / 1000ms^2)
            e.TranslationBehavior = new InertiaTranslationBehavior()
            {
                InitialVelocity = e.InitialVelocities.LinearVelocity,
                DesiredDeceleration = 10.0 * 96.0 / (1000.0 * 1000.0)
            };
            e.Handled = true;

            e.RotationBehavior = new InertiaRotationBehavior();
            e.RotationBehavior.InitialVelocity = e.InitialVelocities.AngularVelocity;
            // 720 degrees per second squared.
            e.RotationBehavior.DesiredDeceleration = 720 / (1000.0 * 1000.0);
        }

                
    }
}
